#ifndef __UPDATEMASK_H
#define __UPDATEMASK_H

class DLL_EXPORT UpdateMask
{
	ui32 *mUpdateMask;
	ui32 mCount; // in values
	ui32 mBlocks; // in ui32 blocks

public:
	UpdateMask( ) : mUpdateMask( 0 ), mCount( 0 ), mBlocks( 0 ) { }
	UpdateMask( const UpdateMask& mask ) : mUpdateMask( 0 ) { *this = mask; }

	~UpdateMask( )
	{
		if(mUpdateMask)
			delete [] mUpdateMask;
	}

	void SetBit( const ui32 index )
	{
		if(index >= mCount)
			return;
		( (ui8 *)mUpdateMask )[ index >> 3 ] |= 1 << ( index & 0x7 );
	}

	void UnsetBit( const ui32 index )
	{
		if(index >= mCount)
			return;
		( (ui8 *)mUpdateMask )[ index >> 3 ] &= (0xff ^ (1 <<  ( index & 0x7 ) ) );
	}

	bool GetBit( const ui32 index ) const
	{
		if(index >= mCount)
			return false;
		return ( ( (ui8 *)mUpdateMask)[ index >> 3 ] & ( 1 << ( index & 0x7 ) )) != 0;
	}

	ui32 GetUpdateBlockCount() const 
	{
		ui32 x;
		for( x = mBlocks - 1; x; x--)
			if(mUpdateMask[x])
				break;

		return (x+1); 
	}
	inline ui32 GetBlockCount() const {return mBlocks;}
	
	inline ui32 GetLength() const { return (mBlocks *sizeof(ui32)); }
	inline ui32 GetCount() const { return mCount; }
	inline const ui8* GetMask() const { return (ui8*)mUpdateMask; }

	void SetCount(ui32 valuesCount)
	{
		if(mUpdateMask)
			delete [] mUpdateMask;

		mCount = valuesCount;
		mBlocks = mCount >> 5;
		if(mCount & 31)
			++mBlocks;

		mUpdateMask = new ui32[mBlocks];
		memset(mUpdateMask, 0, mBlocks *sizeof(ui32));
	}

	void Clear()
	{
		if (mUpdateMask)
			memset(mUpdateMask, 0, mBlocks << 2);
	}

	UpdateMask& operator = ( const UpdateMask& mask )
	{
		SetCount(mask.mCount);
		memcpy(mUpdateMask, mask.mUpdateMask, mBlocks << 2);

		return *this;
	}

	void operator &= ( const UpdateMask& mask )
	{
		if(mask.mCount > mCount)
			return;
		for(ui32 i = 0; i < mBlocks; i++)
			mUpdateMask[i] &= mask.mUpdateMask[i];
	}

	void operator |= ( const UpdateMask& mask )
	{
		if(mask.mCount > mCount)
			return;
		for(ui32 i = 0; i < mBlocks; i++)
			mUpdateMask[i] |= mask.mUpdateMask[i];
	}

	UpdateMask operator & ( const UpdateMask& mask ) const
	{
		UpdateMask newmask;
		if(mask.mCount > mCount)
			return newmask;

		newmask = *this;
		newmask &= mask;

		return newmask;
	}

	UpdateMask operator | ( const UpdateMask& mask ) const
	{
		UpdateMask newmask;
		if(mask.mCount > mCount)
			return newmask;

		newmask = *this;
		newmask |= mask;

		return newmask;
	}
};

#endif